package game

import (
	"bytes"
	"encoding/json"
	"fmt"
	web "geektime-go-homework/web/class4"
	"github.com/google/uuid"
	"github.com/patrickmn/go-cache"
	"html/template"
	"io"
	"net/http"
	"net/url"
	"time"
)

var WxAuthCookieKey = "login_key"
var thirdTokenCookieKey = "third_login_key"

type wxLoginToken struct {
	AccessToken  string        `json:"access_token"`
	RefreshToken string        `json:"refresh_token"`
	ExpireAt     time.Duration `json:"expire_at"`
}

var LoginSession = cache.New(time.Minute*15, time.Second)

type WxSessionUserInfo struct {
	NickName string `json:"nick_name"`
	Region   string `json:"region"`
}

// StartGameServer
//
//	@Description: 游戏服务器， hahagame.com
func StartGameServer() {
	tpl, err := template.ParseGlob("./game/template/*.gohtml")
	if err != nil {
		panic(err)
	}
	engine := &web.GoTemplateEngin{
		T: tpl,
	}
	server := web.NewHttpServer(web.ServerWithTemplateEngine(engine), web.ServerWithMiddleware(LoginMiddlewareGame))

	server.Get("/login", func(ctx *web.Context) {
		var authUrl string
		domain := "http://wxauth.com:8202/authorize"
		q := url.Values{}
		responseType := "code"
		clientId := "wxwaiyouxi123123"
		scope := "userinfo"
		// state 透传字段， 表示客户端状态， 授权后回调跳转会原封不动带上
		state := "firstRegister"
		q.Set("response_type", responseType)
		q.Set("client_id", clientId)
		// 应用的作用域 约束客户端获取access_token后获取信息的作用域
		// 比如 部分用户信息, 完全用户信息, 地域等.
		// 暂时约束 比如 定义
		// userinfo 为 获取用户的 头像， 昵称， 地域
		// base 为 仅仅获取昵称
		q.Set("scope", scope)
		q.Set("state", state)
		queryParams := q.Encode()
		authUrl = domain + "?" + queryParams
		_ = ctx.Render("login.gohtml", map[string]string{"AuthUrl": authUrl})
		return
	})
	server.Get("/token", func(ctx *web.Context) {
		code, _ := ctx.QueryValue("code").AsString()
		bodyStruct := struct {
			Code string `json:"code"`
		}{
			Code: code,
		}
		bodyString, _ := json.Marshal(bodyStruct)
		body := bytes.NewBuffer(bodyString)

		req, verifyErr := http.NewRequest(http.MethodPost, "http://wxauth.com:8202/code/verify", body)

		if verifyErr != nil {
			_ = ctx.RespServerError("解析 token 失败")
			return
		}
		println(req)
		resp, verifySendErr := (&http.Client{}).Do(req)
		if verifySendErr != nil {
			_ = ctx.RespServerError("解析 token 失败")
			return
		}
		tokensBs, _ := io.ReadAll(resp.Body)
		println(string(tokensBs))
		var wxLoginInfo wxLoginToken
		_ = json.Unmarshal(tokensBs, &wxLoginInfo)

		accessTokenSessionId := uuid.New().String()
		cookies := resp.Cookies()
		for _, cookie := range cookies {
			fmt.Sprintf("%s:%s", cookie.Name, cookie.Value)
		}
		ctx.SetCookie(&http.Cookie{
			Name:  WxAuthCookieKey,
			Value: accessTokenSessionId,
		})

		LoginSession.Set(accessTokenSessionId, wxLoginInfo, 15*time.Minute)

		homePage := "http://hahagame.com:8201/index"
		http.Redirect(ctx.Resp, ctx.Req, homePage, 302)
		return
	})
	server.Get("/index", func(ctx *web.Context) {
		accessTokenId, _ := ctx.Req.Cookie(WxAuthCookieKey)
		// 通过accessTokenId获取session 中的 access_token
		get, _ := LoginSession.Get(accessTokenId.Value)
		wxLoginInfoData := get.(wxLoginToken)
		userInfoUrl := fmt.Sprintf("http://wxauth.com:8202/userInfo?access_token=%s", wxLoginInfoData.AccessToken)
		req, buildRequestErr := http.NewRequest(http.MethodGet, userInfoUrl, nil)
		if buildRequestErr != nil {
			homePage := "http://hahagame.com:8201/login"
			http.Redirect(ctx.Resp, ctx.Req, homePage, 302)
			return
		}

		resp, getUserInfoErr := (&http.Client{}).Do(req)
		if getUserInfoErr != nil {
			homePage := "http://hahagame.com:8201/login"
			http.Redirect(ctx.Resp, ctx.Req, homePage, 302)
			return
		}
		userInfoBs, _ := io.ReadAll(resp.Body)

		var userInfo WxSessionUserInfo
		println(string(userInfoBs))
		_ = json.Unmarshal(userInfoBs, &userInfo)

		_ = ctx.Render("index.gohtml", map[string]string{"LoginType": "微信", "NickName": userInfo.NickName, "Region": userInfo.Region})
		return
	})

	server.Start(":8201")
}

func LoginMiddlewareGame(next web.HandleFunc) web.HandleFunc {
	return func(ctx *web.Context) {
		// 登录界面本身不校验
		if ctx.Req.URL.Path == "/login" || ctx.Req.URL.Path == "/token" {
			next(ctx)
			return
		}

		loginId, err := ctx.Req.Cookie(WxAuthCookieKey)

		loginUrl := "http://hahagame.com:8201/login"

		if err != nil {
			http.Redirect(ctx.Resp, ctx.Req, loginUrl, 302)
			return
		}

		_, ok := LoginSession.Get(loginId.Value)
		if !ok {
			http.Redirect(ctx.Resp, ctx.Req, loginUrl, 302)
			return
		}

		next(ctx)
	}
}
